package com.example.armmvvm.ui.fallview

import android.view.View
import android.view.ViewGroup
import android.view.ViewTreeObserver
import androidx.core.view.updateLayoutParams
import androidx.lifecycle.LifecycleOwner
import com.example.armmvvm.ui.view.AnchorSheetBehavior
import com.example.armmvvm.ui.view.IBottomSheetBehavior
import com.example.armmvvm.ui.view.IBottomSheetBehavior.STATE_EXPANDED
import com.example.armmvvm.ui.view.IBottomSheetBehavior.STATE_HIDDEN
import com.google.android.material.bottomsheet.BottomSheetBehavior
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import timber.log.Timber
import kotlin.coroutines.coroutineContext

/**
 * @author 创建人 ：yanghaozhang
 * @version 1.0
 * @package 包名 ：com.augurit.agmobile.agwater5.drainage.pipereview.view
 * @createTime 创建时间 ：2021/3/12
 * @modifyBy 修改人 ：
 * @modifyTime 修改时间 ：
 * @modifyMemo 修改备注：
 */
class AnchorFallViewController private constructor(viewContainer: ViewGroup, lifecycleOwner: LifecycleOwner) :
    BaseFallViewController<AnchorFallViewSetting>(viewContainer, lifecycleOwner) {

    companion object {
        private val BOTTOM_FALL_VIEW_HELPER_LIST: MutableList<AnchorFallViewController> = mutableListOf()

        fun getInstance(viewContainer: ViewGroup, lifecycleOwner: LifecycleOwner): AnchorFallViewController {
            BOTTOM_FALL_VIEW_HELPER_LIST.forEach {
                if (it.lifecycleOwner == lifecycleOwner && viewContainer == it.viewContainer) {
                    return it
                }
            }

            return AnchorFallViewController(viewContainer, lifecycleOwner).also {
                BOTTOM_FALL_VIEW_HELPER_LIST.add(it)
            }
        }
    }

    private val behaviorCallBack = AnchorFallViewStateCallBack()

    val behavior: AnchorSheetBehavior<View> = AnchorSheetBehavior.from(viewContainer)

    var currentFallView: AnchorFallViewSetting? = null

    init {
        lifecycleOwner.lifecycle.addObserver(this)
    }

    override suspend fun showBottomView(
        fallView: AnchorFallViewSetting,
        state: Int
    ) {
        if (isDestroy()) {
            return
        }
        doingJob?.cancel()
        doingJob = coroutineContext[Job]
        val oldFallView = currentFallView
        currentFallView = fallView
        val container = viewContainer
        when {
            container.indexOfChild(fallView.view) == 0 -> {
                oldFallView?.hideCallBack?.invoke()
                behaviorCallBack.reset()
                fallView.behaviorListener?.invoke(behaviorCallBack)
                behavior.setBottomSheetCallback(behaviorCallBack)
                val curState: Int = when {
                    oldFallView?.mode == FallViewMode.ONE_STATE -> state
                    // 展开状态时切换,不改变当前的state
                    behavior.state == BottomSheetBehavior.STATE_EXPANDED -> BottomSheetBehavior.STATE_EXPANDED
                    else -> state
                }
                delay(SHOW_TIME_POST_DELAYED)
                showViewInternal(curState, fallView)
                if (behavior.state == curState) {
                    executeBehaviorCallBack(curState)
                }
            }
            container.childCount > 0 -> {
                hideOldBottomView(oldFallView)
                initNewBottomView(container, fallView)
                delay(SHOW_TIME_POST_DELAYED)
                showViewInternal(state, fallView)
            }
            else -> {
                // 没有子View时,是否需要调用一次hide
                if (fallView.shouldHideBottomView) {
                    hideOldBottomView(oldFallView)
                }
                initNewBottomView(container, fallView)
                delay(SHOW_TIME_POST_DELAYED)
                showViewInternal(state, fallView)
            }
        }

    }

    override fun hideBottomView(): Boolean {
        doingJob?.cancel()
        return if (currentFallView != null) {
            doingJob = coroutineScope.launch {
                if (currentFallView != null) {
                    hideOldBottomView(currentFallView)
                    currentFallView = null
                }
                delay(DISMISS_TIME_POST_DELAYED)
                viewContainer.removeAllViews()
                viewContainer.visibility = View.GONE
            }
            true
        } else {
            false
        }
    }

    override fun isShowing(): Boolean = currentFallView != null && behavior.state != STATE_HIDDEN

    override fun onDestroy() {
        super.onDestroy()
        currentFallView = null
        BOTTOM_FALL_VIEW_HELPER_LIST.remove(this)
    }

    /**
     * FallView因为visible改变了,所以高度发生了改变,但因为behavior高度没有变化
     * 重新计算高度,重新设置state
     */
    fun recalculate() {
        val fallView = currentFallView ?: return
        doingJob?.cancel()
        doingJob = coroutineScope.launch {
            fallView.view.postFlow(if (behavior.state >= STATE_EXPANDED) DISMISS_TIME_POST_DELAYED else -1)
                .catch {
                    it.printStackTrace()
                }
                .collect {
                    Timber.d("Runnable behavior.state::${behavior.state}")
                    if (fallView == currentFallView && behavior.state >= STATE_EXPANDED) {
                        showViewInternal(behavior.state, fallView)
                    } else if (fallView == currentFallView) {
                        recalculate()
                    }
                }
        }
    }

    /**
     * 主动调用一次Behavior的回调
     * 因为当切换FallView时,那么可能不会回调behavior.mCallback
     * hide FallView时,需要回调一次hide,让界面发生变化,然后马上设置[behavior.mCallback]为null
     */
    private fun executeBehaviorCallBack(@IBottomSheetBehavior.State state: Int) {
        if (behavior.mViewRef != null) {
            val view = behavior.mViewRef.get()
            if (view != null && behavior.mCallback != null) {
                // 不计算onSlide百分比数值
                behaviorCallBack.onSlide(view, 0f)
                behaviorCallBack.onStateChanged(view, state, state)
            }
        }
    }

    private fun hideOldBottomView(oldFallView: AnchorFallViewSetting?) {
        behavior.isHideable = true
        behavior.state = STATE_HIDDEN
        executeBehaviorCallBack(STATE_HIDDEN)
        behaviorCallBack.reset()
        oldFallView?.hideCallBack?.invoke()
    }

    private fun initNewBottomView(container: ViewGroup, fallView: AnchorFallViewSetting) {
        val bottomView = fallView.view
        viewContainer.removeAllViews()
        updateParentParams(container, fallView)
        viewContainer.addView(bottomView, bottomView.layoutParams)
        viewContainer.visibility = View.VISIBLE
        behaviorCallBack.reset()
        fallView.behaviorListener?.invoke(behaviorCallBack)
        behavior.setBottomSheetCallback(behaviorCallBack)
    }

    private fun showViewInternal(state: Int, fallView: AnchorFallViewSetting) {
        val view = fallView.view
        if (fallView.mode == FallViewMode.ONE_STATE) {
            if (view.height == 0) {
                view.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
                    override fun onGlobalLayout() {
                        view.viewTreeObserver.removeOnGlobalLayoutListener(this)
                        behavior.peekHeight = view.height
                        behavior.anchorHeight = view.height
                        updateBehaviorState(fallView, state)
                    }
                })
            } else {
                behavior.peekHeight = view.height
                behavior.anchorHeight = view.height
                updateBehaviorState(fallView, state)
            }
        } else {
            if (view.height == 0) {
                view.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
                    override fun onGlobalLayout() {
                        view.viewTreeObserver.removeOnGlobalLayoutListener(this)
                        fallView.calcHeight?.invoke(view)
                        behavior.peekHeight = fallView.peekHeight
                        behavior.anchorHeight = fallView.anchorHeight
                        updateBehaviorState(fallView, state)
                    }
                })
            } else {
                fallView.calcHeight?.invoke(view)
                behavior.peekHeight = fallView.peekHeight
                behavior.anchorHeight = fallView.anchorHeight
                updateBehaviorState(fallView, state)
            }
        }
    }

    private fun updateBehaviorState(fallView: AnchorFallViewSetting, state: Int) {
        behavior.isAllowDragdown = fallView.mode != FallViewMode.ONE_STATE
        behavior.state = state
        behavior.isHideable = fallView.hideable
    }

    private fun updateParentParams(container: View, fallView: AnchorFallViewSetting) {
        // ONE_STATE:自适应高度,展示在底部;如果是MATCH_PARENT会导致显示在顶部
        container.updateLayoutParams {
            height =
                if (fallView.mode == FallViewMode.ONE_STATE
                    || fallView.mode == FallViewMode.TWO_NO_TOP_STATE
                    || fallView.mode == FallViewMode.THREE_NO_TOP_STATE
                )
                    ViewGroup.LayoutParams.WRAP_CONTENT
                else
                    ViewGroup.LayoutParams.MATCH_PARENT
        }
    }
}